package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;

public class ConnectionListener extends Thread {

	private Server server;
	private ServerSocket ss;
	private final int port = 4444;
	private Hashtable outputStreams = new Hashtable();

	public ConnectionListener(Server server) throws IOException{
		this.server = server;
		start();
	}

	public void run(){
		try {
			listen(port);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void listen(int port) throws IOException{

		ss = new ServerSocket(port);

		while (true){
			Socket s = ss.accept();
			System.out.println( "Establishing connection to " + s );
			server.logln("Connection from client at " +s.getInetAddress());
			DataOutputStream dout = new DataOutputStream( s.getOutputStream() );
			outputStreams.put(s, dout);
			new ClientHandler(server,s,this);

		}
	}

	Enumeration getOutputStreams() {
		return outputStreams.elements();
	}
	
    void sendToAll( String message ) {
        // We synchronize on this because another thread might be
        // calling removeConnection() and this would screw us up
        // as we tried to walk through the list
        synchronized( outputStreams ) {
                // For each client ...
                for (Enumeration e = getOutputStreams(); e.hasMoreElements(); ) {
                        // ... get the output stream ...
                        DataOutputStream dout = (DataOutputStream)e.nextElement();
                        // ... and send the message
                        try {
                                dout.writeUTF( message );
                        } catch( IOException ie ) { System.out.println( ie ); }
                }
        }
}

	void removeConnection( Socket s ) {
		// Synchronize so we don't mess up sendToAll() while it walks
		// down the list of all output streamsa
		synchronized( outputStreams ) {
			// Log in the console
			System.out.println( "Removing connection to " + s );
			//Log in the GUI
			// Remove it from our hashtable/list
			outputStreams.remove( s );
			// Make sure it's closed
			try {
				s.close();
			} catch( IOException ie ) {
				System.out.println( "Error closing "+s );
				ie.printStackTrace();
			}
		}
	}
}

class ClientHandler extends Thread {

	private Socket socket;
	private Server server;
	private LocalNode localNode;
	private ConnectionListener connectionListener;

	public ClientHandler(Server server, Socket socket, ConnectionListener cl){
		this.server = server;
		this.socket = socket;
		if(server != null)
			this.localNode = server.getLocalNode('2');
		else
			System.out.println("The server is null...");
		this.connectionListener = cl;
		start();

	}

	public void run(){
		try{
			DataInputStream din = new DataInputStream(socket.getInputStream());
			while (true) {
				// ... read the next message ...
				String message = din.readUTF();
				// Log the information
				server.logln( socket + " " + message);
				server.getGUI().sendToClient();
				// ... and have the server send it to all clients
			}

		}
		catch (IOException e){
			e.printStackTrace();
		}
		finally{
			connectionListener.removeConnection(socket);
		}
	}
}
